#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"

#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_main.h"

#include "nvs.h"
#include "nvs_flash.h"

#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_https_ota.h"
#include "esp_http_client.h"

#include "driver/spi_master.h"

#include "driver/adc.h"
#include "esp_adc_cal.h"

#include "driver/timer.h"

#include "main.h"

//--------------------------↓全局变量↓--------------------------//
uint8_t  MCU_ON_flag=0;		//开机标志位
uint8_t  MCU_OFF_flag=0;	//关机标志位
uint8_t  OTAupgrade_Version = 0xA4;	//OTA版本固定,优化BLE固件
uint8_t  Debug_set = 1;		//为0正常模式、为1调试模式
uint8_t  ChargingStart=0;	//充电开启位
uint8_t  SystemLaunch=0;	//系统启动位

static uint16_t STM_Version = 0x1BFF;//固定写死模拟stm32版本号
static uint8_t  ElecQ = 0; //电量
static uint8_t TPC_TAG = 0; //0：发送指令    1：发送数据
static char MAC_Name[20] = {0};//Bt和Ble需要用到的mac变量值
static char  wifi_STA_SSID[32],wifi_STA_PASS[64];
static uchar ack_OK[4] = {0x6A,0xA6,0x04,0xA1};	//应答:(空闲、成功)
static uchar ack_NO[4] = {0x6A,0xA6,0x04,0xA0};	//应答:(忙碌、失败)

User_parameter_val_t UserParm_val={0,0,0};//用户参数

static void adc_Initialize_handler(void);
static esp_err_t esp_nvs_launch_read_handler(void);
static void FLASH_WriteByte(uint8_t WriteDat);
void BleSetDeviceDiscovery(void);

//--------------------------↑全局变量↑--------------------------//


//--------------------------↓用户函数↓--------------------------//
uint8_t testFlag=0;
static void User_reserves(void *pvParameters){	//储备队列数据
	IO_Init();//IO引脚初始化
	Time_Init();//定时器初始化
	usart1_init();//串口接收数据初始化
	Ink308_Initialize();//喷墨引脚驱动初始化
	adc_Initialize_handler();//adc初始化
	esp_nvs_launch_read_handler();//nvs启动读取用户数据
	FLASH_PicCnt_Read();//flash读取图片数据
 	while(1){
		
		//-----------------------printf------------------------
		if(testFlag){
			testFlag = 0;
			printf("\ntestFlag!!\n");
		}
		
		//-------------------------关机-------------------------
		if(MCU_OFF_flag){
			MCU_OFF_flag = 0;
			if(!Chg_Get)Led_set(0); 					 //非充电状态灯光全灭，和充电状态下的流水灯设置避开
			FLASH_Counter_Storage();
			Pwr_OFF;									 //PWR_ON_CTR/IO9引脚设置为低，即关机掉电
		}
		
		//---------------------充电状态---------------------
		if(Chg_Get){
			//关机流水灯和关闭蓝牙搜索
			if(!MCU_ON_flag&&!ChargingStart){
				ChargingStart = 1;
				Led_set(0);								//灯光全灭
				LedPm.number = 0x01;
				LedPm.twinkle = 1;
				LedPm.runcount = 5000;//0.5秒闪烁
				esp_ble_gap_stop_advertising(); 		//蓝牙不允许被发现和连接
			}
			//开机打开蓝牙搜索
			else if(MCU_ON_flag&&SystemLaunch==1){
				SystemLaunch = 2;						//避免二次进入
				BleSetDeviceDiscovery();				//蓝牙允许被发现和连接
			}
		}
		
		//-----------------------ADC刷新-----------------------
		if(adcTimeRead&&MCU_ON_flag&&!TPC_TAG){
			adcTimeRead = 0;
			adc_Refresh_handler();
		}

		//---------------------计数器刷新----------------------
		if(CountReflash){
			CountReflash = 0;
			TimCntTask();
		}

		//---------------------传完图处理----------------------
		if(ReadyPrintFlag == 2){
			ReadyPrintFlag = 1;
			vTaskDelay(100/portTICK_PERIOD_MS);
			TimCntTask();//刷新计数器
			vTaskDelay(100/portTICK_PERIOD_MS);
			esp_nvs_write_handler(NVS_key_PicLen,&data_length,sizeof(data_length));//存储数据长度
			Beep_set(200);//传图完毕蜂鸣器响
			LED5_ON;
		}
		
		//--------------------清除图片数据---------------------
		if(ResetESP32count >= 5){//连按5下
			ResetESP32count = 0;
			data_length = 0;
			vTaskDelay(500/portTICK_PERIOD_MS);		  //避免蜂鸣器突然被打断
			FLASH_WriteByte(0);
			vTaskDelay(100/portTICK_PERIOD_MS);
			esp_nvs_write_handler(NVS_key_PicLen,&data_length,sizeof(data_length));//清除存储数据长度
			gpio_intr_disable(Pluse_IO);				  //关闭外部引脚中断
			Beep_set(500);
			LED5_OFF;									  //打印灯灭
			ReadyPrintFlag = 0;
			StartPrintFlag = 0;
		}

		//----------------------USB传图(传图速度很慢，后面继续优化)-----------------------
		if(MCU_ON_flag){
			USBControl_Pic();//指令接收图片
			if(Test_Printdata){//将测试图复制进打印函数
				Print_TestData();
			}		
		}

		//------------------------OTA--------------------------
		//在开启蓝牙情况下进行OTA大概45s~1min左右
		 if(esp_pb_stu_flg.ota_start_upgrade_flg){
		 	
			 esp_bluedroid_disable();//断开蓝牙，否则BT在连接中会导致OTA升级中断
			 esp_bt_controller_disable();
			 vTaskDelay(100/portTICK_PERIOD_MS);

			 if(Debug_set)ESP_LOGI(OTA_UPGRADE_TAG, "Starting OTA example\n");
			 esp_http_client_config_t config = {
				 .url = ota_upgrade_url_val,
			 };
		  	 
			 esp_err_t ret = esp_https_ota(&config);
			 if (ret == ESP_OK) {//升级成功
				 Beep_set(300);
				 if(Debug_set)ESP_LOGI(OTA_UPGRADE_TAG, "OTA upgrade success!!\n");
			 } else {			 //升级失败
				 BeepExp_set(100,3);
				 if(Debug_set)ESP_LOGE(OTA_UPGRADE_TAG, "OTA upgrade failed!!\n");
			 }
			 vTaskDelay(100/portTICK_PERIOD_MS);
			 esp_restart();
		 }

		//----------------------Delay函数---------------------
		vTaskDelay(100/portTICK_PERIOD_MS);
	}
}
//--------------------------↑用户函数↑--------------------------//


//--------------------------↓User_nvs↓------------------------------//
#define STORAGE_NAMESPACE 	"storage"

esp_err_t esp_nvs_read_handler(char* nvs_key_name,void *nvs_value){
	esp_err_t err;
	nvs_handle_t mynvs_handle;
	timer_pause(Timer0_group, Timer0_BeepLed);//关闭定时器，否则nvs和flash功能无法使用，会导致系统直接崩溃
	timer_pause(Timer0_group, Timer0_Button);
	//nvs_open是直接调用分区中带有标签“nvs”的分区	nvs_open_from_part这个则是可以指定带有“nvs”的指定名称分区
	err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &mynvs_handle);
	if (err != ESP_OK) {
		if(Debug_set)
			ESP_LOGE(ESP_NVS_TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    } else {
    
		size_t required_size = 0;

		 // Read the size of memory space required for blob 
		err = nvs_get_blob(mynvs_handle, nvs_key_name, NULL, &required_size);
		if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
		
		//再来读取对应的值
   		 err = nvs_get_blob(mynvs_handle, nvs_key_name, nvs_value, &required_size);
		if (err ==ESP_OK )
		{
			if(Debug_set)
				ESP_LOGE(ESP_NVS_TAG, "Nvs Read success!\n");
		}
		else 
		{
			if(Debug_set)
				ESP_LOGE(ESP_NVS_TAG, "read err =0x%x\n",err);
			return err;
		} 
		nvs_close(mynvs_handle);		//关闭句柄
    }
	timer_start(Timer0_group, Timer0_BeepLed);
	timer_start(Timer0_group, Timer0_Button);
	return ESP_OK;
}

esp_err_t esp_nvs_write_handler(char* nvs_key_name,void *nvs_value,uint len){
    esp_err_t err;
    nvs_handle_t mydata_nvs;
    // Open nvs
	timer_pause(Timer0_group, Timer0_BeepLed);//关闭定时器，否则nvs和flash功能无法使用，会导致系统直接崩溃
	timer_pause(Timer0_group, Timer0_Button);
    err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &mydata_nvs);
    if (err != ESP_OK)
    {
        if(Debug_set)
			ESP_LOGE(ESP_NVS_TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
        return err;
    }
    err = nvs_set_blob(mydata_nvs, nvs_key_name, nvs_value, len);
    if (err == ESP_OK)
    {
        if(Debug_set)
			ESP_LOGI(ESP_NVS_TAG, "Nvs Write success!\n");
    }
	else 
	{
		if(Debug_set)
			ESP_LOGE(ESP_NVS_TAG, "read err =0x%x\n",err);
		return err;
	}
    ESP_ERROR_CHECK(nvs_commit(mydata_nvs));
    nvs_close(mydata_nvs);
	timer_start(Timer0_group, Timer0_BeepLed);
	timer_start(Timer0_group, Timer0_Button);
    return ESP_OK;
}

//NVS读取
static esp_err_t esp_nvs_launch_read_handler(void){

	esp_err_t err;	
//--------------------------用户设置参数--------------------------//	
	err = esp_nvs_read_handler(NVS_key_Set,Parameter_Array);
	if(err!=ESP_OK){//读取错误则重新设置默认值
		SetCommand_Value = 0x03;
		Print_Timecount = 0;
		Parameter_Array[0] = SetCommand_Value;
		Parameter_Array[1] = Print_Timecount>>8;
		Parameter_Array[2] = Print_Timecount;
		esp_nvs_write_handler(NVS_key_Set,Parameter_Array,sizeof(Parameter_Array));
	}else{
		SetCommand_Handle(Parameter_Array[0]);
		Print_Timecount = Parameter_Array[1]<<8;	 // 间隔时间
		Print_Timecount|= Parameter_Array[2];
		if(Debug_set)
			ESP_LOGE(ESP_NVS_TAG, "SetCommand_Value:%d,Print_Timecount:%d\n",SetCommand_Value,Print_Timecount);
	}
	
//----------------------------喷墨次数----------------------------//	
	err = esp_nvs_read_handler(NVS_key_InkC,&PrintInkCount);
	if(err!=ESP_OK){//读取错误则设置默认值
	    PrintInkCount = InkPrtCnt;//默认次数
	    esp_nvs_write_handler(NVS_key_InkC,&PrintInkCount,sizeof(PrintInkCount));
	}else{
		if(PrintInkCount<1||PrintInkCount>5)		// 喷墨次数
		   PrintInkCount = InkPrtCnt;//默认次数
		if(Debug_set)ESP_LOGE(ESP_NVS_TAG, "PrintInkCount:%d\n",PrintInkCount);
	}
	
//----------------------------喷墨脉宽----------------------------//	
	err = esp_nvs_read_handler(NVS_key_InkP,&PrintInkPluse);
	if(err!=ESP_OK){//读取错误则设置默认值
		PrintInkPluse=InkPrtPluse;//默认脉宽
		esp_nvs_write_handler(NVS_key_InkP,&PrintInkPluse,sizeof(PrintInkPluse));
	}else{
		if(PrintInkPluse<2||PrintInkPluse>50)		// 喷墨脉宽
		   PrintInkPluse=InkPrtPluse;//默认脉宽
		if(Debug_set)ESP_LOGE(ESP_NVS_TAG, "PrintInkPluse:%d\n",PrintInkPluse);
	}

//--------------------------图片数据长度--------------------------//	
	err = esp_nvs_read_handler(NVS_key_PicLen,&data_length);
	if(err!=ESP_OK){//读取错误则设置默认值
		data_length = 0;					//数据长度
		ReadyPrintFlag = 0;
		esp_nvs_write_handler(NVS_key_PicLen,&data_length,sizeof(data_length));
	}else{
		if(data_length>7) ReadyPrintFlag = 1;
		else ReadyPrintFlag = 0;
		if(Debug_set)ESP_LOGE(ESP_NVS_TAG, "ReadyPrintFlag:%d,data_length:%d\n",ReadyPrintFlag,data_length);
	}
	return ESP_OK;
}
//--------------------------↑User_nvs↑--------------------------//


//----------------------------↓ADC↓----------------------------//
static void adc_Initialize_handler(void){
    adc1_config_width(ADC_WIDTH_BIT_12); 
    adc1_config_channel_atten(ADC1_CHANNEL_3,ADC_ATTEN_DB_12);
	adc_Refresh_handler();
}

uint8_t adcTimeRead=0;
void adc_Refresh_handler(void){//电量刷新处理函数
	int adcValue=0,_result=0;
	for(int x=0;x<10;x++){
		adcValue += adc1_get_raw(ADC1_CHANNEL_3);
		vTaskDelay(10/portTICK_PERIOD_MS);
	}
	
	//需要在开机模式下判断
	if(MCU_ON_flag){
		if(adcValue<19600){			//电池电压低于6.8V,电量过低直接报警关机，避免电池欠压
		    BeepExp_set(100,3);
			MCU_ON_flag = 0;		//开机标志位清0
			Beep_set(500);
		}
		
		if(adcValue<20200)			//电池电压为7V时,则低电压电量灯提醒
		   LED4_OFF;	 	 		//低电量灭灯
		else
		   LED4_ON;	 		 		//电量正常亮灯
	}
	
	_result = (adcValue/10)-1960;	//6.8V,对应的ADC值约等于1960，8.1V,对应的ADC值为2360
	_result = _result/80+1; 		//2360-1960=400,所以分为5份，每份80，+1是为了能达到5
	if(_result>5)
	   _result=5;					//最大不能超过5
	if(Chg_Get)
		ElecQ = 0xFF;				//显示充电状态标志
	else
		ElecQ = _result;
	if(Debug_set)printf("adcValue:%d,elec:%d\n",adcValue/10,ElecQ);
}

//----------------------------↑ADC↑----------------------------//


//----------------------------↓Flash↓----------------------------//
static const char *TAG = "user_flash";
static const esp_partition_t *partition;

static void init_usr_flash(void){//寻找分区表
    partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "user_save");
    assert(partition != NULL);
}

static void FLASH_WriteByte(uint8_t WriteDat){   //在指定地址写入数组
    uint8_t err=0;
	uint32_t FlashSize=0;
	timer_pause(Timer0_group, Timer0_BeepLed);
	timer_pause(Timer0_group, Timer0_Button);//因为存储Flash数据比较大，所以10ms的定制器也得关闭，否则flash功能无法使用，会导致系统直接崩溃
	FlashSize =  ((int)(data_length/4096)+1)*4096;
	if(Debug_set)printf("erase_FlashSize:%d\n",FlashSize);
    //擦除flash
    err=esp_partition_erase_range(partition, 0, FlashSize);
    if(err!=0)
    {
        ESP_LOGI(TAG, "user flash erase error %d\n",err);
    }
	if(WriteDat){//1:写数据   	/ 0:擦存储
	    //写入flash
	    err = esp_partition_write(partition, 0, RxBuf, FlashSize);
	    if(err!=0)
	    {
	        ESP_LOGI(TAG, "user flash write error %d\n",err);
	    }
	}
 	timer_start(Timer0_group, Timer0_BeepLed);
	timer_start(Timer0_group, Timer0_Button);
}

void FLASH_ReadByte(void){//在指定地址读出数组
	uint8_t  err =0;
	uint32_t FlashSize=0;
	timer_pause(Timer0_group, Timer0_BeepLed);
	timer_pause(Timer0_group, Timer0_Button);//因为存储Flash数据比较大，所以10ms的定制器也得关闭，否则flash功能无法使用，会导致系统直接崩溃
	FlashSize =  ((int)(data_length/4096)+1)*4096;
	//读取flash
    err=esp_partition_read(partition, 0, RxBuf, FlashSize);
    if(err!=0)
    {
        ESP_LOGI(TAG, "user flash read erro %d\n",err);
        return ;
    }
 	timer_start(Timer0_group, Timer0_BeepLed);
	timer_start(Timer0_group, Timer0_Button);
}
//----------------------------↑Flash↑----------------------------//


//--------------------------↓WIFI_AP↓--------------------------//

#define EXAMPLE_AP_WIFI_SSID	   	"Evebot_xxxx"
#define EXAMPLE_AP_WIFI_PASS   		"12345678"
#define EXAMPLE_MAX_AP_CONN    		4

static void ap_event_handler(void* arg, esp_event_base_t event_base,
                                    int32_t event_id, void* event_data){
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        if(Debug_set)ESP_LOGI(WIFI_AP_TAG, "station "MACSTR" join, AID=%d\n",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        if(Debug_set)ESP_LOGI(WIFI_AP_TAG, "station "MACSTR" leave, AID=%d\n",
                 MAC2STR(event->mac), event->aid);
    }
}
static void wifi_init_softap(void){
	if(esp_pb_stu_flg.wifi_launch_ap_sta_flg == 1){	//防止重复连接操作
		if(Debug_set)ESP_LOGI(WIFI_AP_TAG,"AP is connected already!\n");
		return;
	}if(esp_pb_stu_flg.esp_launch_wifi_stu_flg<2){
		esp_netif_create_default_wifi_ap();		//使其能够连接到 TCP/IP 软件栈 开机后只能启动一次
		esp_pb_stu_flg.esp_launch_wifi_stu_flg++;
	}
	if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"AP is starting!\n");
		
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//指定需要初始化底层的参数信息
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));		//wifi初始化
	//事件处理回调函数
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &ap_event_handler, NULL));

    wifi_config_t wifi_config = {
        .ap = {
            //.ssid = EXAMPLE_AP_WIFI_SSID,
            //.ssid_len = strlen(EXAMPLE_AP_WIFI_SSID),
            .password = EXAMPLE_AP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_AP_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };
	strcpy((char*)wifi_config.ap.ssid,MAC_Name);//设置ap的SSID
    if (strlen(EXAMPLE_AP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));//设置wifi模式为AP模式
   	//将wifi_config初始值进行配置wifi
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());			//启动wifi
	
	esp_pb_stu_flg.wifi_stu_type_flg = 0;		//AP模式开启成功置位
	esp_pb_stu_flg.wifi_launch_ap_sta_flg = 1;	//AP完成一次启动

	if(Debug_set)ESP_LOGI(WIFI_AP_TAG, "wifi init softap finished. SSID:%s password:%s\n",
             EXAMPLE_AP_WIFI_SSID, EXAMPLE_AP_WIFI_PASS);

	if(esp_pb_stu_flg.esp_launch_wifi_stu_flg<2){//下面函数开机只能调用一次
	    //实现了AP下通过流量上网
	    //借鉴代码:https://github.com/qmsk/esp/blob/f6c27e8686017e3b8a9dae0fc314580a02b65f2f/main/esp8266/wifi_tcpip_adapter.c 
	    /*设置HDPC前先要停止HDCP*/
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"AP Set HDCP!!!\n");
	    tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP);
	    uint8_t dhcps_offer_router = 0;
	    //关闭Route路由
	    tcpip_adapter_dhcps_option(TCPIP_ADAPTER_OP_SET, TCPIP_ADAPTER_ROUTER_SOLICITATION_ADDRESS, &dhcps_offer_router, sizeof(dhcps_offer_router));
	    //关闭DNS
	    uint8_t dhcps_offer_dns = 0;
	    tcpip_adapter_dhcps_option(TCPIP_ADAPTER_OP_SET, TCPIP_ADAPTER_DOMAIN_NAME_SERVER, &dhcps_offer_dns, sizeof(dhcps_offer_dns));
	    //ESP_LOGI(WIFI_TAG, "DHCP ROUTER_SOLICITATION_ADDRESS:%d",dhcps_offer_router);
	    //设置完成后要启动DHCP
	    tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP);
	}
}

#define DEFAULT_SCAN_LIST_SIZE  10//太多会出现堆栈溢出
void scanNetworks(void){
	uint16_t number = DEFAULT_SCAN_LIST_SIZE;
    wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
    uint16_t ap_count = 0;
    memset(ap_info, 0, sizeof(ap_info));
	
	// 配置 WiFi 模块
	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
	// 设置 WiFi 模式为 STA（Station 模式）
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    // 启动WiFi
    ESP_ERROR_CHECK(esp_wifi_start());
    // 开始扫描可用的WIFI热点
    ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, true));
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));

	ESP_LOGI(WIFI_TAG, "Total APs scanned = %u", ap_count);

	uint8_t recv_data[304] = {0x6A,0xA6,4,5,0}; //返回的数据
	uint16_t SSID_len=0,x;
	recv_data[4] = (DEFAULT_SCAN_LIST_SIZE<ap_count?DEFAULT_SCAN_LIST_SIZE:ap_count);
    for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) {
		for(x=0;x<30;x++){
			if(ap_info[i].ssid[x]=='\0')break;
			recv_data[6+SSID_len+x]=ap_info[i].ssid[x];
		}
		recv_data[5+SSID_len]=x;
		SSID_len+=x+1;
        ESP_LOGI(WIFI_TAG, "x= %d , SSID %s  SSID_len:%d", x,ap_info[i].ssid,SSID_len);
    }
	SendToApp(5+SSID_len,recv_data);
	esp_wifi_stop();//不停止wifi的话，后面切换STA模式会出问题
}
//--------------------------↑WIFI_AP↑--------------------------//



//--------------------------↓WIFI_STA↓--------------------------//

#define EXAMPLE_STA_MAXIMUM_RETRY  2	//STA尝试重复连接次数

static EventGroupHandle_t s_wifi_event_group;

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static int s_retry_num = 0;

static void sta_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data){
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();								//连接wifi——STA
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"STA is starting!\n");
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_STA_MAXIMUM_RETRY) {	//连接失败，重新尝试连接
            esp_wifi_connect();
            s_retry_num++;
            if(Debug_set)ESP_LOGI(WIFI_STA_TAG, "retry to connect to the AP\n");
        } else {
				//置位事件组中的失败BIT标志位
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);	
			if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"connect to the AP fail\n");	//最终连接失败
			s_retry_num = 0;
        }
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        if(Debug_set)ESP_LOGI(WIFI_STA_TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));//连接成功，读取IP值
        s_retry_num = 0;
//user
	 	for(uchar i=0;i<4;i++){//sta获取IP值存储在数组中方便使用
			user_prefer_val.sta_IP_val[i] = esp_ip4_addr_get_byte(&event->ip_info.ip,i);
		}
		//sta获取MAC值存储在数组中方便使用
		esp_read_mac(user_prefer_val.sta_mac_val,ESP_MAC_WIFI_STA);

		//最终连接成功置位事件组的成功BIT标志位
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);	
    }
}
static uint8_t wifi_init_sta(void){	
	uint8_t error = 0xff;
	if(esp_pb_stu_flg.wifi_launch_ap_sta_flg == 2){	//防止重复连接操作
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"STA is connected already!\n");
		return 1;
	}
	if(esp_pb_stu_flg.esp_launch_wifi_stu_flg<2){
		esp_netif_create_default_wifi_sta();		//此函数未调用会无法获取IP	开机后只能启动一次	
		esp_pb_stu_flg.esp_launch_wifi_stu_flg++;
	}
	if((wifi_STA_SSID[0]=='\0')||(wifi_STA_PASS[0]=='\0')){
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG,"Wifi SSID and PASS is null !!!\n");
			//user
			wifi_init_softap();			//如果SSID和PASS有空的现象，重置AP模式
		return 0;
	}

	wifi_config_t wifi_config={0};//此处需要初始化值0，否则会STA启动失败！！！
	s_wifi_event_group = xEventGroupCreate();//创建事件组

	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));	//初始化wifi
	//设置回调函数
	ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &sta_event_handler, NULL));
	ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &sta_event_handler, NULL));

	strcpy((char*)wifi_config.sta.ssid,wifi_STA_SSID);	//将SSID和PASS值传入至STA配置的结构体中
	strcpy((char*)wifi_config.sta.password,wifi_STA_PASS);

	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));	//设置WIFI模式为STA模式
	//将wifi_config初始值进行配置wifi
	ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
	ESP_ERROR_CHECK(esp_wifi_start());				//启动WIFI

	EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
			WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
			pdFALSE,
			pdFALSE,
			portMAX_DELAY);							//事件组在这里进行延时等待BIT标志位置位
	
	esp_pb_stu_flg.wifi_launch_ap_sta_flg = 2;		//STA完成一次启动
	if (bits & WIFI_CONNECTED_BIT) {
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG, "connected to ap SSID:%s password:%s\n",
				 wifi_STA_SSID, wifi_STA_PASS);
		esp_pb_stu_flg.wifi_stu_type_flg = 1;		//STA模式开启成功置位		
	} else if (bits & WIFI_FAIL_BIT) {
		if(Debug_set)ESP_LOGI(WIFI_STA_TAG, "Failed to connect to SSID:%s password:%s\n",
				 wifi_STA_SSID, wifi_STA_PASS);
		wifi_init_softap();							//一旦STA切换失败之后要重新启动AP模式
		error = 0;
	} else {
		ESP_LOGE(WIFI_STA_TAG, "UNEXPECTED EVENT\n");
		error = 0;
	}

	//撤销事件回调函数
	ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &sta_event_handler));
	ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &sta_event_handler));
	vEventGroupDelete(s_wifi_event_group);		//关闭事件组
	return error;
}

//--------------------------↑WIFI_STA↑--------------------------//


//--------------------------↓BLE_SPP↓--------------------------//
#define SPP_PROFILE_NUM             1
#define SPP_PROFILE_APP_IDX         0
#define ESP_SPP_APP_ID              0x56
#define SPP_SVC_INST_ID	            0
/// SPP Service
static const uint16_t spp_service_uuid = 0xABF0;
/// Characteristic UUID
#define ESP_GATT_UUID_SPP_COMM_RECEIVE      0xABF1
#define ESP_GATT_UUID_SPP_REPLY_RECEIVE     0xABF2
#define ESP_GATT_UUID_SPP_DATA_RECEIVE      0xAB01
								
static uint8_t spp_adv_data[17] = {
	0x02,0x01,0x06,
	0x03,0x03,0xF0,0xAB,
	0x09,0x09,'E','V','E','_','X','X','X','X',
};

static uint16_t spp_mtu_size = 23;
static uint16_t spp_conn_id = 0xffff;
static esp_gatt_if_t spp_gatts_if = 0xff;
static bool enable_data_ntf = false;
static bool is_connected = false;
static esp_bd_addr_t spp_remote_bda = {0x0,};
static uint16_t spp_handle_table[SPP_IDX_NB];

static esp_ble_adv_params_t spp_adv_params = {
	.adv_int_min		= 0x20,
	.adv_int_max		= 0x40,
	.adv_type			= ADV_TYPE_IND,
	.own_addr_type		= BLE_ADDR_TYPE_PUBLIC,
	.channel_map		= ADV_CHNL_ALL,
	.adv_filter_policy	= ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

static void array_combination_handler(void *array1,void *array2,int len){
	char* array_1,*array_2;
	array_1 = (char*)array1;
	array_2 = (char*)array2;
	
	for(int i=0;i<len;i++){
		array_1[i] = array_2[i];
	}
	array_1[len] = '\0';		//因为入口参数是一个字符串数组，所以最后一定要加结束符！！！
	array1 = (void*)array_1;
}

// 允许被其他设备搜索
void BleSetDeviceDiscovery(void) {
	esp_ble_adv_params_t adv_params = {
		.adv_int_min = 0x20,
		.adv_int_max = 0x40,
		.adv_type = ADV_TYPE_IND,
		.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
		.channel_map = ADV_CHNL_ALL,
		.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY
	};

	esp_ble_gap_start_advertising(&adv_params);
}

void SendToApp(uint8_t len,uchar* val)
{
	if(UserParm_val.Ble_WriteHdl)//避免出现蓝牙没有连接就调用这个函数
		esp_ble_gatts_send_indicate(UserParm_val.Ble_gatts_if, UserParm_val.Ble_conn_id,
			UserParm_val.Ble_WriteHdl,len,val,false);
}

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

static struct gatts_profile_inst spp_profile_tab[SPP_PROFILE_NUM] = {
    [SPP_PROFILE_APP_IDX] = {
        .gatts_cb = gatts_profile_event_handler,
        .gatts_if = ESP_GATT_IF_NONE,
    },
};

#define CHAR_DECLARATION_SIZE   (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;

static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE_NR;
static const uint8_t char_prop0_read_write = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop1_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ;

///SPP Service - data receive characteristic, read&write without response
static const uint16_t spp_comm_receive_uuid = ESP_GATT_UUID_SPP_COMM_RECEIVE;
static const uint8_t  spp_comm_receive_val[20] = {0x00};

static const uint16_t spp_reply_receive_uuid = ESP_GATT_UUID_SPP_REPLY_RECEIVE;
static const uint8_t  spp_reply_receive_val[20] = {0x00};

static const uint16_t spp_data_receive_uuid = ESP_GATT_UUID_SPP_DATA_RECEIVE;
static const uint8_t  spp_data_receive_val[20] = {0x00};



static const esp_gatts_attr_db_t spp_gatt_db[SPP_IDX_NB] = {
    //SPP -  Service Declaration
    [SPP_IDX_SVC]                      	=
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
    sizeof(spp_service_uuid), sizeof(spp_service_uuid), (uint8_t *)&spp_service_uuid}},

    //SPP -  data receive characteristic Declaration
    [SPP_IDX_SPP_COMM_RECV_CHAR]            =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
    CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}},

    [SPP_IDX_SPP_COMM_RECV_VAL]             =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_comm_receive_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
    SPP_DATA_MAX_LEN,sizeof(spp_comm_receive_val), (uint8_t *)spp_comm_receive_val}},

    [SPP_IDX_SPP_REPLY_RECV_CHAR]            =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
    CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop0_read_write}},

    [SPP_IDX_SPP_REPLY_RECV_VAL]             =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_reply_receive_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
    SPP_DATA_MAX_LEN,sizeof(spp_reply_receive_val), (uint8_t *)spp_reply_receive_val}},

    //SPP -  data receive characteristic Declaration
    [SPP_IDX_SPP_DATA_RECV_CHAR]            =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
    CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop1_read_write}},

    [SPP_IDX_SPP_DATA_RECV_VAL]             =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&spp_data_receive_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
    SPP_DATA_MAX_LEN,sizeof(spp_data_receive_val), (uint8_t *)spp_data_receive_val}},

};
static uint8_t find_char_and_desr_index(uint16_t handle){
    uint8_t error = 0xff;
    for(int i = 0; i < SPP_IDX_NB ; i++){
        if(handle == spp_handle_table[i]){
            return i;
        }
    }
    return error;
}
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){
    esp_err_t err;
    switch (event) {
    case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
        esp_ble_gap_start_advertising(&spp_adv_params);
        break;
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        if((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
            if(Debug_set)
				ESP_LOGE(BLE_SPP_TAG, "Advertising start failed: %s\n", esp_err_to_name(err));
        }
        break;
    default:
        break;
    }
}

void PrintfCmd(uchar num,uint8_t* data){
	if(Debug_set){
		printf("ESP32 to APP:6A A6 ");
		for(uint8_t z=2;z<num;z++)
			if(Debug_set)printf("%X ",data[z]);
		printf(" \n ");
	}
}

uint32_t data_length = 0;//数据总长度
static uint32_t data_length_ing = 0; //当前数据长度
static uint16_t data_pack_index = 0; //当前数据包的索引

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){
	uint8_t res = 0xff;
    switch (event) {
    	case ESP_GATTS_REG_EVT:
    	    if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "%s %d\n", __func__, __LINE__);
        	esp_ble_gap_set_device_name((const char*)MAC_Name);

        	if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "%s %d\n", __func__, __LINE__);
        	esp_ble_gap_config_adv_data_raw((uint8_t *)spp_adv_data, sizeof(spp_adv_data));

        	if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "%s %d\n", __func__, __LINE__);
        	esp_ble_gatts_create_attr_tab(spp_gatt_db, gatts_if, SPP_IDX_NB, SPP_SVC_INST_ID);
       	break;
    	case ESP_GATTS_READ_EVT:
			break;
    	case ESP_GATTS_WRITE_EVT: {
    	    res = find_char_and_desr_index(param->write.handle);
            if(param->write.is_prep == false){
				 UserParm_val.Ble_WriteHdl = 40+SPP_IDX_SPP_REPLY_RECV_VAL; //保存蓝牙发送数据句柄
				 UserParm_val.Ble_gatts_if = gatts_if;
				 UserParm_val.Ble_conn_id = param->write.conn_id;
				 
                 if(res == SPP_IDX_SPP_COMM_RECV_VAL){
					 //user
					 #if 1
					 char* ble_data = (char *)param->write.value;
					 	
					 if(ble_data[0]==0x6A && ble_data[1]==0xA6){
						 Tim_Countdown = 0;//有传输则清空倒计时
						 switch(ble_data[2])
						 {
							 case 2:{ //询问请求状态  6A A6 02 xx xx
							 	 TPC_TAG = 0;
								 switch(ble_data[3]){
									 case 0x01:{//APP发送请求发送照片
									 		if(StartPrintFlag){
												uint8_t resp_data[4] = {0x6A,0xA6,0x3,0x2};//应答打印中
												SendToApp(sizeof(resp_data),resp_data);
												PrintfCmd(4,resp_data);
											}else{
												PhotoDate_Handle(ble_data,5,ble_data[4]);
												if(only_count)
													vTaskDelay(1000/portTICK_PERIOD_MS);		//此处加延时是防止出现传图完毕指令和下面的打印中指令冲突
											}
									 		break;}
									 case 0xA4: {//APP发送设置指令,并存入FLASH
									 		uint8_t resp_data[4] = {0x6A,0xA6,0x3,0xD};//应答设置成功
											SendToApp(sizeof(resp_data),resp_data);
									 		PrintfCmd(4,resp_data);
									 		SetCommand_Handle(ble_data[4]);
											Print_Timecount =(uint16_t)ble_data[5]<<8;
             								Print_Timecount |=(uint16_t)ble_data[6];
											Parameter_Array[0] = SetCommand_Value;
											Parameter_Array[1] = Print_Timecount>>8;
											Parameter_Array[2] = Print_Timecount;
											esp_nvs_write_handler(NVS_key_Set,Parameter_Array,sizeof(Parameter_Array));
											Beep_set(100);
									 		break;}
									 case 0xA5: {//APP向STM32请求参数
									 		uint8_t resp_data[16] = {0x6A,0xA6,0x3,0xA,0,0,0,0,0,0,0,0,0,0,0,0};//应答设置参数
											resp_data[8] = SetCommand_Value;
											resp_data[9] = Print_Timecount>>8;
											resp_data[10] = Print_Timecount;
											SendToApp(sizeof(resp_data),resp_data);
											PrintfCmd(16,resp_data);
									 		break;}
									 case 0xAC: {//APP向STM32发送打印是否结束询问
											if(!StartPrintFlag){
										 		uint8_t resp_data[4] = {0x6A,0xA6,0x3,0xC};//应答打印结束指令
												SendToApp(sizeof(resp_data),resp_data);
												PrintfCmd(4,resp_data);
											}
											break;}
									 case 0xB3: {//app设置单点喷墨次数
											PrintInkCount = ble_data[4];
											esp_nvs_write_handler(NVS_key_InkC,&PrintInkCount,sizeof(PrintInkCount));
											Beep_set(100);
											break;}
									 case 0xB4: {//app设置喷墨脉宽
											PrintInkPluse = ble_data[4];
											esp_nvs_write_handler(NVS_key_InkP,&PrintInkPluse,sizeof(PrintInkPluse));
											Beep_set(100);
											break;}
									 default:break;
								 }								 
								 break;}
							 case 5:{
							 	 uint8_t resp_data[9] = {0x6A,0xA6,0x4,0x4,0,0,0,0,0};//APP向ESP32获取当前ESP32的版本号
								 resp_data[4] = OTAupgrade_Version;
								 resp_data[5] = (uint8_t)(STM_Version>>8);
								 resp_data[6] = (uint8_t)STM_Version;
								 resp_data[7] = ElecQ;
								 resp_data[8] = StartPrintFlag;
								 SendToApp(sizeof(resp_data),resp_data);
								 PrintfCmd(9,resp_data);
								 break;}
							 case 6:{//OTA升级指令
								 //存储上位机发来的SSID和PASS值，要注意这两个值的数组是字符串数组，转移的时候要注意加结束符！！！
								 array_combination_handler(wifi_STA_SSID,&ble_data[5],ble_data[3]);
								 array_combination_handler(wifi_STA_PASS,&ble_data[5+ble_data[3]],ble_data[4]);
								 if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "SSID:%s   PASS:%s \n",wifi_STA_SSID,wifi_STA_PASS);
					 
								 //接受URL
								 ota_upgrade_url_val = malloc(ble_data[5+ble_data[3]+ble_data[4]]+1);//给指针分配空间地址，否则堆栈会溢出
								 array_combination_handler(ota_upgrade_url_val,&ble_data[5+ble_data[3]+ble_data[4]+1],ble_data[5+ble_data[3]+ble_data[4]]);
								 if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "len:%d url:%s\n", ble_data[5+ble_data[3]+ble_data[4]],ota_upgrade_url_val);
								 
								 //WIFI_STA初始化
								 uchar err;
								 err = wifi_init_sta();
								 if(err == 0xff){//STA切换成功
								 	 SendToApp(sizeof(ack_OK),ack_OK);
									 if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "BLE_STA success!!\n");
									 esp_pb_stu_flg.ota_start_upgrade_flg = 1;//开启OTA升级
									 Beep_set(200);//开启OTA升级，让下位机响一声提醒
								 }
								 else{
								 	 SendToApp(sizeof(ack_NO),ack_NO);
									 if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "BLE_STA failed!!\n");
								 }
								 break;}
							 case 7:{
							 	 scanNetworks();
							 	 break;}
							 default:
								 break;
						}
					 }
				    #endif
				 }
				 else if(res == SPP_IDX_SPP_DATA_RECV_VAL){
	  				   char* ble_data = (char *)param->write.value;
	  				   int ble_len = param->write.len;

					   //开始发包 6A A6 01 xx xx xx xx
	  				   if(ble_data[0]==0x6A && ble_data[1]==0xA6 && ble_data[2]==0x1 && !TPC_TAG){
						   //获取包的总长度
						   data_length =  (ble_data[3] << 24) + (ble_data[4] << 16) + (ble_data[5] << 8) + ble_data[6];
						   //补上指令长度
						   data_length += 7;//包头长度为7
						   //当前数据长度设置零
						   data_length_ing = 0;
						   //设置第几个包
						   data_pack_index = 0;
						   //设置状态发送中
						   TPC_TAG = 1;
						   //清除图案预备标志位
						   ReadyPrintFlag = 0;
						   //清除空间内容
						   memset(RxBuf,0,data_length);
						   if(Debug_set)printf("data_length:%d \n",data_length);
	  				   }

					   //开始接受图片数据
	  				   if(TPC_TAG==1){
							
						   array_combination_handler(&RxBuf[data_length_ing],ble_data,ble_len);//接收图片数据
					   	   
	  					   //当前数据长度叠加
	  					   data_length_ing += ble_len;
	  					   data_pack_index++;
	  					   //if(Debug_set)printf("BLE_LEN:%d!\n",data_length_ing);

						   
	  					   if(!(data_pack_index%10)){
						   	   uint8_t resp_data[5] = {0x6A,0xA6,0x4,0x3,0};
	  						   uint32 _Percent = data_length/100;
	  						   resp_data[4] = (char)(data_length_ing/_Percent);
							   SendToApp(sizeof(resp_data),resp_data);//接受数据百分比
	  					   }
	  					   
	  					   //发送完毕
	  					   if (data_length_ing >= data_length) {
	  						   data_length_ing = 0;
							   data_pack_index = 0;
						   	   Last_PrintDateNum = data_length;
							   uint8_t resp_data[4] = {0x6A,0xA6,0x4,0x2};
							   SendToApp(sizeof(resp_data),resp_data);//告诉APP传输到100%
							   PrintfCmd(4,resp_data);
							   vTaskDelay(100/portTICK_PERIOD_MS);
	  						   if(Print_FlashSwitch)//存储flash数据
								   FLASH_WriteByte(1);
							   uint8_t resp_data1[4] = {0x6A,0xA6,0x3,0x8};
	  						   SendToApp(sizeof(resp_data1),resp_data1);//告诉客户端发送完毕
	  						   PrintfCmd(4,resp_data1);
						  	   if(Debug_set)printf("BLE send Pic finsh!\n");
							   ReadyPrintFlag = 2;					//预备打印标志位传完图先置2,然后处理完应答指令后再置1
							   StartPrintFlag = 1;					//每次传完图就开启打印，傻瓜式操作。
							   gpio_intr_enable(Pluse_IO);			//允许外部引脚中断
	  						   TPC_TAG = 0; //清除发送状态
	  					   }
	  				   }
	            }
      	 	break;
    	}
    	case ESP_GATTS_EXEC_WRITE_EVT:
    	    break;
    	case ESP_GATTS_MTU_EVT:
    	    spp_mtu_size = param->mtu.mtu;
			if(Debug_set)printf("MTU Size:%d \n",spp_mtu_size);
    	    break;
    	case ESP_GATTS_CONF_EVT:
    	    break;
    	case ESP_GATTS_UNREG_EVT:
        	break;
    	case ESP_GATTS_DELETE_EVT:
        	break;
    	case ESP_GATTS_START_EVT:
        	break;
    	case ESP_GATTS_STOP_EVT:
        	break;
    	case ESP_GATTS_CONNECT_EVT:
			LED2_TWK_OFF;
			LED2_ON;
			BeepExp_set(100,2);//连接成功让下位机蜂鸣器响
			esp_ble_gap_stop_advertising();//不允许被发现和连接
    	    spp_conn_id = param->connect.conn_id;
    	    spp_gatts_if = gatts_if;
    	    is_connected = true;
    	    memcpy(&spp_remote_bda,&param->connect.remote_bda,sizeof(esp_bd_addr_t));
        	break;
    	case ESP_GATTS_DISCONNECT_EVT:
			if(!esp_pb_stu_flg.ota_start_upgrade_flg){//得不在OTA中断开才进行响声
				LED2_TWK_ON;
				BeepExp_set(100,2);//断开连接让下位机蜂鸣器响
			}
			BleSetDeviceDiscovery();//允许被发现和连接
			UserParm_val.Ble_WriteHdl = 0; //清除蓝牙发送数据句柄
    	    is_connected = false;
    	    enable_data_ntf = false;
    	    esp_ble_gap_start_advertising(&spp_adv_params);
    	    break;
    	case ESP_GATTS_OPEN_EVT:
    	    break;
    	case ESP_GATTS_CANCEL_OPEN_EVT:
    	    break;
    	case ESP_GATTS_CLOSE_EVT:
    	    break;
    	case ESP_GATTS_LISTEN_EVT:
    	    break;
    	case ESP_GATTS_CONGEST_EVT:
    	    break;
    	case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
    	    if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "The number handle =%x\n",param->add_attr_tab.num_handle);
    	    if (param->add_attr_tab.status != ESP_GATT_OK){
    	        if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "Create attribute table failed, error code=0x%x", param->add_attr_tab.status);
    	    }
    	    else if (param->add_attr_tab.num_handle != SPP_IDX_NB){
    	        if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "Create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, SPP_IDX_NB);
    	    }
    	    else {
    	        memcpy(spp_handle_table, param->add_attr_tab.handles, sizeof(spp_handle_table));
    	        esp_ble_gatts_start_service(spp_handle_table[SPP_IDX_SVC]);
    	    }
    	    break;
    	}
    	default:
    	    break;
    	}
    }
}

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            spp_profile_tab[SPP_PROFILE_APP_IDX].gatts_if = gatts_if;
        } else {
            if(Debug_set)ESP_LOGI(BLE_SPP_TAG, "Reg app failed, app_id %04x, status %d\n",param->reg.app_id, param->reg.status);
            return;
        }
    }
    do {
        int idx;
        for (idx = 0; idx < SPP_PROFILE_NUM; idx++) {
            if (gatts_if == ESP_GATT_IF_NONE || // ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function 
                    gatts_if == spp_profile_tab[idx].gatts_if) {
                if (spp_profile_tab[idx].gatts_cb) {
                    spp_profile_tab[idx].gatts_cb(event, gatts_if, param);
                }
            }
        }
    } while (0);
}

//--------------------------↑BLE_SPP↑--------------------------//


//--------------------------↓BT_Controller↓--------------------------//

void bt_controller_handler(void){
    esp_err_t ret;
	
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
       if(Debug_set)ESP_LOGE(SPP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        if(Debug_set)ESP_LOGE(SPP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }
    ret = esp_bluedroid_init();
    if (ret) {
        if(Debug_set)ESP_LOGE(SPP_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
	    }
   ret = esp_bluedroid_enable();
    if (ret) {
        if(Debug_set)ESP_LOGE(SPP_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

//BLE初始化
	esp_ble_gatts_register_callback(gatts_event_handler);
	esp_ble_gap_register_callback(gap_event_handler);
	esp_ble_gatts_app_register(ESP_SPP_APP_ID);	
}

//--------------------------↑BT_Controller↑--------------------------//
//打印芯片信息值
static void print_userinfo_handler(void){
	static uint8_t mac[6] = {0};
	strcpy((char*)MAC_Name,BTMAC_TAG);	//存入“EVE_”
	esp_read_mac(mac,ESP_MAC_BT);	//读取MAC值
	sprintf(&MAC_Name[4],"%02X%02X",mac[4],mac[5]);//把数据变为字符串写入数组中
	spp_adv_data[13] = (mac[4]>>4)>9?(mac[4]>>4)+55:(mac[4]>>4)+48;
	spp_adv_data[14] = (mac[4]&0x0f)>9?(mac[4]&0x0f)+55:(mac[4]&0x0f)+48;
	spp_adv_data[15] = (mac[5]>>4)>9?(mac[5]>>4)+55:(mac[5]>>4)+48;
	spp_adv_data[16] = (mac[5]&0x0f)>9?(mac[5]&0x0f)+55:(mac[5]&0x0f)+48;
	if(Debug_set){
		ESP_LOGI(USER_TAG,"-------------- Get Systrm Info----------------------\n");
		//打印MAC值
		ESP_LOGI(USER_TAG,"	 BT Name: %s\n", MAC_Name);
		//获取IDF版本
		ESP_LOGI(USER_TAG,"	 SDK version: %s\n", esp_get_idf_version());
		//获取芯片可用内存
		ESP_LOGI(USER_TAG,"	 Free heap size : %d Kb  \n", esp_get_free_heap_size()/1024);
		ESP_LOGI(USER_TAG,"----------------------------------------------------\n\n");
	}
}

void app_main(void){
	esp_err_t ret;

	ret = nvs_flash_init(); //占12K
	if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
		 ESP_ERROR_CHECK(nvs_flash_erase());
		 ret = nvs_flash_init();
	 }
	ESP_ERROR_CHECK(ret);
	
	if(Debug_set)ESP_LOGE(OTA_UPGRADE_TAG, "Run ota_0!!!\n");
//打印用户信息
	print_userinfo_handler();

//寻找分区表
	init_usr_flash();
	
//蓝牙启动模式设置	(当前为BLE模式)
	bt_controller_handler();//bluedroid占650K左右
	
//用户任务函数
	xTaskCreate(User_reserves, "User_reserves", 1024*10, NULL, 1, NULL);

    return;
}


